import { Constructor, Node } from "cc";
import { ArrayQueue } from "../../struct/ArrayQueue";
import { ArrayStack } from "../../struct/ArrayStack";
import { ProxyBase } from "../proxy/ProxyBase";
import { proxyMgr } from "../proxy/ProxyMgr";
import { UIBase } from "./UIBase";
import { uiMgr } from "./UIMgr";
import { UIInfo, UICMD, UIState, UIExtral, UICoverAction, UICommand, UIBackTopAction } from "./BaseTypes";

/**
 * ui管理
 */
export class UIPipeline {
    /** 
     * 水位线(保留关闭界面的数量
     */
    private _water: number = 0;
    /** 
     * UI根节点 
     */
    private _uiRoot: Node = null;
    /** 
     * 信息 
     */
    private _infoMap: Map<string, UIInfo> = new Map();
    /** 
     * 命令队列 
     */
    private _cmdQueue: ArrayQueue<UICommand> = new ArrayQueue();
    /**
     * 要显示的队列
     */
    private _showStack: ArrayStack<UIInfo> = new ArrayStack();


    private _lock: boolean = false;

    /**
     * 通过队列命令刷新ui
     */
    private async _updateUI() {
        if (this._cmdQueue.isEmpty()) return;
        if (this._lock) return;

        this._lock = true;
        const cmdData = this._cmdQueue.dequeue()

        // 显示命令
        if (cmdData.cmd == UICMD.SHOW) {
            const info = this.getInfo(cmdData.proxyName)
            info.extral = cmdData.extral
            if (info.state == UIState.SHOW) {
                console.warn(`uiMgr>>>${cmdData.proxyName}---CMD.SHOW---UIState.SHOW`)
                this._refreshShow(info)
            } else {
                await this._showUI(info)
            }
        }
        // 关闭命令
        else if (cmdData.cmd == UICMD.CLOSE) {
            const info = this.getInfo(cmdData.proxyName)
            switch (info.state) {
                case UIState.NONE:
                    console.warn(`uiMgr>>>${cmdData.proxyName}---CMD.CLOSE---UIState.NONE`)
                    break;
                case UIState.CLOSE:
                    console.warn(`uiMgr>>>${cmdData.proxyName}---CMD.CLOSE---UIState.CLOSE`)
                    break;
                case UIState.COVER:
                    this._closeUI(info)
                    break
                case UIState.SHOW:
                    this._closeUI(info)
                    this._backTopUI()
                    break;
            }
        }
        // 关闭全部
        else if (cmdData.cmd == UICMD.CLOSE_ALL) {
            while (!this._showStack.isEmpty()) {
                const info = this._showStack.peek()
                if (info.state != UIState.COVER && info.state != UIState.SHOW) {
                    console.error(`uiMgr>>>${cmdData.proxyName}---CMD.CLOSE_ALL---UIState==>${info.state}`)
                } else {
                    this._closeUI(this._showStack.pop())
                }
            }
        }
        // 返回到某一界面
        else if (cmdData.cmd == UICMD.BACKTO) {
            const info = this._infoMap.get(cmdData.proxyName)
            if (this._showStack.has(info)) {
                while (this._showStack.peek() != info) {
                    const tempInfo = this._showStack.peek()
                    if (tempInfo.state != UIState.COVER && tempInfo.state != UIState.SHOW) {
                        console.error(`uiMgr>>>${tempInfo.proxyName}---CMD.CLOSE_LAYER---UIState==>${tempInfo.state}`)
                        break
                    } else {
                        this._closeUI(this._showStack.pop())
                    }
                }
            }
        }

        cmdData.finishCallback && cmdData.finishCallback()
        this._lock = false;
        this._updateUI()
    }

    /**
     * 重新显示
     * @param info 
     */
    private _refreshShow(info: UIInfo) {
        if (info.state != UIState.SHOW) return
        const wnd = proxyMgr.getWnd(info.proxyName, info.uuid) as UIBase<ProxyBase>;
        // 设置节点显示
        wnd.view.node.active = true;
        wnd.args = info.extral?.data ?? {};
        wnd.onShow()
        info.extral?.showCallback && info.extral.showCallback()
    }

    /**
     * 显示
     * @param info 
     */
    private async _showUI(info: UIInfo) {
        const topInfo = this._showStack.peek()
        if (info == topInfo) {
            console.error(`${info.proxyName}------状态为不显示，但在栈顶`)
            return
        }
        this._showStack.remove(info)
        this._showStack.push(info)
        if (info.state == UIState.NONE) {
            const wndIns = await proxyMgr.createWnd(info.proxyName, this._uiRoot)
            info.uuid = wndIns.uuid
        }

        info.state = UIState.SHOW
        this._refreshShow(info)

        if (topInfo) {
            topInfo.state = UIState.COVER
            const topWnd = proxyMgr.getWnd(topInfo.proxyName, topInfo.uuid) as UIBase<ProxyBase>;
            const meta = uiMgr.getUIMeta(topInfo.proxyName);
            // 判断是否需要隐藏
            if (meta.cover == UICoverAction.HIDE)
                topWnd.view.node.active = false;
            else if (meta.cover == UICoverAction.SHOW)
                topWnd.view.node.active = true;
            topWnd.onCover(info.proxyName);
        }
    }

    /**
     * 隐藏
     * @param info 
     */
    private _closeUI(info: UIInfo) {
        this._showStack.remove(info)
        info.state = UIState.CLOSE
        const wnd = proxyMgr.getWnd(info.proxyName, info.uuid) as UIBase<ProxyBase>;
        wnd.onClose();
        info.extral?.closeCallback && info.extral.closeCallback()
    }

    /**
     * 返回到顶部
     */
    private _backTopUI() {
        if (this._showStack.isEmpty()) return
        const topInfo = this._showStack.peek()
        if (topInfo.state != UIState.COVER) {
            console.error(`${topInfo.proxyName}------topInfo.state != UIState.COVER}`)
            return
        }
        topInfo.state = UIState.SHOW;
        const topWnd = proxyMgr.getWnd(topInfo.proxyName, topInfo.uuid) as UIBase<ProxyBase>;
        const meta = uiMgr.getUIMeta(topInfo.proxyName);
        // 判断是否需要隐藏
        if (meta.backTop == UIBackTopAction.HIDE)
            topWnd.view.node.active = false;
        else if (meta.backTop == UIBackTopAction.SHOW)
            topWnd.view.node.active = true;
        topWnd.onBackTop();
    }

    /**
     * 检查可释放的ui
     */
    private _checkReleaseUI() {
        let canReleases: UIInfo[] = [];
        for (const [k, v] of this._infoMap.entries()) {
            if (v.state == UIState.CLOSE) {
                canReleases.push(v);
            }
        }
        let releaseCount = canReleases.length - this._water;
        for (let i = 0; i < releaseCount; i++) {
            const info = canReleases[i]
            const wnd = proxyMgr.getWnd(info.proxyName, info.uuid)
            // 释放
            proxyMgr.releaseWnd(wnd)
            // 重置状态
            info.state = UIState.NONE
            info.uuid = null
            info.extral = null
        }
    }

    /**
     * 初始化UI管理器
     */
    init(uiRoot: Node, water: number = 0) {
        this._uiRoot = uiRoot;
        this._water = water;
    }

    /**
     * 显示UI界面
     * @param proxyClass 代理类
     * @param extral 扩展数据
     * @returns Promise
     */
    show(proxyClass: Constructor<ProxyBase> | string, extral?: UIExtral) {
        return new Promise<void>((resolve) => {
            this._checkReleaseUI()
            const proxyName = typeof proxyClass === 'string' ? proxyClass : proxyClass.name;
            this._cmdQueue.enqueue({ cmd: UICMD.SHOW, proxyName, extral, finishCallback: resolve })
            this._updateUI();
        })
    }

    /**
     * 关闭
     */
    close(proxyClass: Constructor<ProxyBase> | string) {
        const proxyName = typeof proxyClass === 'string' ? proxyClass : proxyClass.name;
        this._cmdQueue.enqueue({ cmd: UICMD.CLOSE, proxyName })
        this._updateUI()
        this._checkReleaseUI()
    }

    /**
     * 关闭所有
     */
    closeAll() {
        this._cmdQueue.enqueue({ cmd: UICMD.CLOSE_ALL })
        this._updateUI()
        this._checkReleaseUI()
    }

    /**
     * 返回到指定界面
     * @param proxyClass 
     * @returns 
     */
    backToTop(proxyClass: Constructor<ProxyBase> | string) {
        const proxyName = typeof proxyClass === 'string' ? proxyClass : proxyClass.name;
        this._checkReleaseUI()
        this._cmdQueue.enqueue({ cmd: UICMD.BACKTO, proxyName })
        this._updateUI()
    }

    /**
     * 主动释放(只有已关闭界面才行)
     */
    release(proxyClass: Constructor<ProxyBase> | string) {
        const proxyName = typeof proxyClass === 'string' ? proxyClass : proxyClass.name;
        const info = this._infoMap.get(proxyName)
        if (info.state == UIState.CLOSE) {
            const wnd = proxyMgr.getWnd(proxyName, info.uuid);
            proxyMgr.releaseWnd(wnd)
        }
    }

    /**
     * 主动释放所有(只有已关闭界面才行)
     */
    releaseAll() {
        for (const [k, v] of this._infoMap.entries()) {
            if (v.state == UIState.CLOSE) {
                const wnd = proxyMgr.getWnd(v.proxyName, v.uuid);
                proxyMgr.releaseWnd(wnd)
            }
        }
    }

    /**
     * 获取UI信息
     * @param proxyClass 
     * @returns 
     */
    getInfo(proxyClass: Constructor<ProxyBase> | string) {
        const proxyName = typeof proxyClass === 'string' ? proxyClass : proxyClass.name;
        if (!this._infoMap.has(proxyName))
            this._infoMap.set(proxyName, new UIInfo(proxyName))
        return this._infoMap.get(proxyName)
    }
}